<?php
/**
 * 学生作业信息模型
 */
class Taskinfo_model extends CI_Model {
    /**
     * 构造方法，用来创建数据表
     */
    public function __construct() {
        if ($this->db->table_exists('taskinfo') != true) {
            $this->creatTaskinfoTable();
        }
    }
    /**
     * 创建学生作业信息数据表
     * 先设置字段，再设置索引
     * @return void
     */
    public function creatTaskinfoTable() {
        // 加载数据库工厂类
        $this->load->dbforge();
        // 设置字段信息
        $fields = array(
            'stu_id'    => array(
                'type'           => 'INT',
                'constraint'     => 5,
                'unsigned'       => TRUE,
                'auto_increment' => TRUE,
            ),
            'stuname'   => array(
                'type'       => 'VARCHAR',
                'constraint' => '100',
            ),
            'stunumber' => array(
                'type'       => 'VARCHAR',
                'constraint' => '10',
            ),
            'stuclass'  => array(
                'type'       => 'INT',
                'constraint' => '1',
            ),
            'stuurl'    => array(
                'type'       => 'VARCHAR',
                'constraint' => '200',
            ),
        );
        // 添加字段
        $this->dbforge->add_field($fields);
        // 设置索引
        $this->dbforge->add_key('stu_id', TRUE);
        $this->dbforge->add_key('stuname');
        $this->dbforge->add_key('stuclass');
        // 根据以上信息创建表
        $this->dbforge->create_table('taskinfo');
    }
    /**
     * 存储学生提交的信息
     * @param array $data 用户提交信息
     * @return void
     */
    public function add(array $data) {
        $this->db->insert('taskinfo', $data);
    }
    /**
     * 获取taskinfo表中的所有信息
     * 然后以数组的形式返回
     * @return array 表中的全部信息
     */
    public function getAll() {
        return $this->db->get('taskinfo')->result_array();
    }
    /**
     * 生成学期周次节点
     * @param  string $start 课程开始日期
     * @return array 		 包含19周上课时间节点的数组
     */
    public function weekly($start = '2017-8-30') {
        for ($i = 0; $i < 19; $i++) {
            $data[$i] = strtotime("+" . $i . " week", strtotime($start));
        }
        return $data;
    }
    /**
     * 获取学生仓库存储所在的网站、用户名和仓库名称
     * @param  string $str	学生仓库地址
     * @return mixed 		如果匹配成功，则返回数组，否则返回false
     */
    public function getUserRepo($str = '') {
        // 去掉.git
        $pattern = '/.git$/';
        $str     = preg_replace($pattern, '', $str);
        // 获取站点、用户名、仓库名
        $pattern = '@\/\/(.*?)\/(.*?)\/(.*)@';
        if (preg_match($pattern, $str, $matched)) {
            $data['site']     = $matched[1];
            $data['username'] = $matched[2];
            $data['repo']     = $matched[3];
            return $data;
        } else {
            return false;
        }
    }
    /**
     * 使用curl库获取在线信息
     * @param  string  $url    在线地址
     * @param  boolean $decode 是否将json转化为数组
     * @return mixed           字符串或者数组
     */
    public function getOnlineData($url = '', $decode = TRUE) {
        // 初始化curl
        $ch = curl_init($url);
        //
        // 设置cURL配置项
        //
        // CURLOPT_HEADER 为真时，在输出结果中包含header信息
        // CURLOPT_RETURNTRANSFER 为真时，将结果以字符串的形式返回，为假时，结果直接在浏览器中显示
        //
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 从证书中检查SSL加密算法是否存在
        // 执行crul，并将返回的结果保存到变量$data中。
        $data = curl_exec($ch);
        // 将json数据转换为数组
        if ($decode) {
            $data = json_decode($data, true);
        }
        // 关闭curl资源
        curl_close($ch);
        // var_dump($data);
        return $data;
    }
    /**
     * 获取gitee.com站点的推送信息
     * @param  string $user 用户名
     * @param  string $repo 仓库名
     * @return array        数组格式的推送信息
     */
    public function getGiteeCommits($user = '', $repo = '') {
        // 拼接gitee API地址
        $url = "https://gitee.com/api/v5/repos/" . $user . "/" . $repo . "/commits";
        // 获取数组
        $data = $this->getOnlineData($url);
        return $data;
    }
    /**
     * 获取coding.net站点的推送信息
     * @param  string $user 用户名
     * @param  string $repo 仓库名
     * @return array        数组格式的推送信息
     */
    public function getCodingnetCommits($user = '', $repo = '') {
        // 拼接gitee API地址
        $url = "https://coding.net/api/user/" . $user . "/project/" . $repo . "/git/commits/master%252F?page=1&pageSize=50";
        // 获取数组
        $data = $this->getOnlineData($url);
        if (isset($data['data']['commits']['list'])) {
            return $data['data']['commits']['list'];
        } else {
            return false;
        }
    }
    /**
     * 获取每周作业推送次数
     * @param  array  $commits 学生作业推送信息数组
     * @return array           学生每周作业推送次数
     */
    public function getCommitByWeek(array $commitDate = array()) {
        // 先得到学期时间节点
        $week = $this->weekly();
        // 初始化数组
        $array = array();
        // 逐一比较
        for ($i = 0; $i < 19; $i++) {
            $array[$i] = 0;
            foreach ($commitDate as $key => $value) {
                if ($value >= $week[$i] && $value <= $week[$i + 1]) {
                    $array[$i]++;
                }
            }
        }
        return $array;
    }
    /**
     * 获取gitee.com站点中的作业推送日期
     * @param  array  $commits 作业信息原始数组
     * @return mixed           作业推送日期或者false
     */
    public function getGiteeCommitDate(array $commits = array()) {
        foreach ($commits as $key => $value) {
            // 2017-11-15T17:54:42+08:00,提取其日期
            // 首先判断是否有值
            if (isset($value['commit']['author']['date'])) {
                $array[$key] = strtotime($value['commit']['author']['date']);
            } else {
                return false;
            }
        }
        return $array;
    }
    /**
     * 获取coding.net站点中的作业推送日期
     * @param  array  $commits 作业信息原始数组
     * @return array           作业推送日期
     */
    public function getCodingnetCommitDate(array $commits = array()) {
        foreach ($commits as $key => $value) {
            // commitTime	1498376546000
            // 需要截取前十位字符组成时间
            if (isset($value['commitTime'])) {
                $array[$key] = substr($value['commitTime'], 0, 10);
            } else {
                return false;
            }
        }
        return $array;
    }
    /**
     * 返回具体学生作业信息，包括提交次数和提交周次
     * @param  integer $id	学生在数据库中的编号
     * @return mixed   		包含学生信息的多维数组
     */
    public function creatStuTaskInfo($id = 0) {
        // 获取指定用户信息
        $array = array('stu_id' => $id);
        $data  = $this->db->where($array)->get('taskinfo')->result_array();
        // 获取用户名、站点信息、仓库信息
        $data['userrepo'] = $this->getUserRepo($data[0]['stuurl']);
        // 针对gitee.com站点获取信息
        if ($data['userrepo']['site'] == 'git.oschina.net' || $data['userrepo']['site'] == 'gitee.com') {
            // 获取gitee.com全部推送信息
            $data['totalcommits'] = $this->getGiteeCommits($data['userrepo']['username'], $data['userrepo']['repo']);
            // 分析并生成推送信息的日期信息
            if ($data['totalcommits']) {
                $data['commitDate'] = $this->getGiteeCommitDate($data['totalcommits']);
                if ($data['commitDate']) {
                    // 生成每周推送次数信息
                    $data['weekly'] = $this->getCommitByWeek($data['commitDate']);
                    return $data;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
        if ($data['userrepo']['site'] == 'git.coding.net') {
            // 获取coding.net全部推送信息
            $data['totalcommits'] = $this->getCodingnetCommits($data['userrepo']['username'], $data['userrepo']['repo']);
            // 分析并生成推送信息的日期信息
            if ($data['totalcommits']) {
                $data['commitDate'] = $this->getCodingnetCommitDate($data['totalcommits']);
                if ($data['commitDate']) {
                    // 生成每周推送次数信息
                    $data['weekly'] = $this->getCommitByWeek($data['commitDate']);
                    return $data;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
        // 如果不是上述站点，则返回假
        return false;
    }
}
